
using Xeralabs.Core.Utils.Timing;
using System;
using System.Collections.Generic;

namespace Xeralabs.Core
{
    internal class KernelTimer
    {
        private static List<SimulaTimer> _timers;
        private static int _nextIndex = 0;

        private static List<int> _freeIndexes;
        private static int _freeIndex = -1;

        private static List<double> _lastTimeouts;
        private static List<double> _lastElapsed;


        private KernelTimer() { }   //NO CREABLE

        /// <summary>
        /// Constructor.
        /// </summary>
        static KernelTimer() { }

        internal static int StartTimer()
        {
            if (_timers == null)
            {
                _timers = new List<SimulaTimer>();
                _lastTimeouts = new List<double>();
                _lastElapsed = new List<double>();
            }

            int index = _nextIndex;

            if (_freeIndex > -1)
            {
                index = _freeIndexes[_freeIndex];
                _freeIndexes.RemoveAt(_freeIndex);
                _freeIndex--;

                if (_timers[index] == null)
                {
                    //ERROR EL TIMER NO ESTABA? QUE PASO NENG?
                    _timers[index] = new SimulaTimer();
                }
            }
            else
            {
                _timers.Add(new SimulaTimer());
                _lastTimeouts.Add(0.0);
                _lastElapsed.Add(0.0);
                _nextIndex++;
            }

            _timers[index].Start();
            _timers[index].Reset();
            return index;
        }
        internal static void StopTimer(int timerIndex)
        {
            if ((_timers != null) && (timerIndex < _timers.Count))
            {
                if (_freeIndexes == null)
                {
                    _freeIndexes = new List<int>();
                    _freeIndex = -1;
                }

                if ((_timers[timerIndex] != null) && (!_timers[timerIndex].IsStopped))
                {
                    _timers[timerIndex].Stop();
                }

                _lastTimeouts[timerIndex] = 0.0;
                _lastElapsed[timerIndex] = 0.0;

                _freeIndexes.Add(timerIndex);
                _freeIndex++;
            }
        }

        internal static void ResetTimer(int timerIndex)
        {
            if (timerIndex >= _nextIndex)
                throw new ArgumentOutOfRangeException("timerIndex", timerIndex, "El valor del parametro timerIndex excede el numero de temporizadores existentes");
            
            if (_timers[timerIndex] != null)
            {
                _timers[timerIndex].Reset();
                _lastTimeouts[timerIndex] = 0.0;
                _lastElapsed[timerIndex] = 0.0;
            }
        }
        internal static void Advance(int timerIndex)
        {
            if (timerIndex >= _nextIndex)
                throw new ArgumentOutOfRangeException("timerIndex", timerIndex, "El valor del parametro timerIndex excede el numero de temporizadores existentes");
            
            if ((_timers[timerIndex] != null) && (!_timers[timerIndex].IsStopped))
            {
                _timers[timerIndex].Advance();
                _lastTimeouts[timerIndex] = _timers[timerIndex].GetTime();
                _lastElapsed[timerIndex] = _timers[timerIndex].GetElapsedTime();
            }
        }

        internal static double GetAbsoluteTime(int timerIndex)
        {
            if (timerIndex >= _nextIndex)
                throw new ArgumentOutOfRangeException("timerIndex", timerIndex, "El valor del parametro timerIndex excede el numero de temporizadores existentes");
            if ((_timers[timerIndex] == null) || (_timers[timerIndex].IsStopped))
                throw new InvalidOperationException();

            return _timers[timerIndex].GetAbsoluteTime();
        }
        internal static double GetTime(int timerIndex)
        {
            if (timerIndex >= _nextIndex)
                throw new ArgumentOutOfRangeException("timerIndex", timerIndex, "El valor del parametro timerIndex excede el numero de temporizadores existentes");
            if ((_timers[timerIndex] == null) || (_timers[timerIndex].IsStopped))
                throw new InvalidOperationException();
            if (!_timers[timerIndex].IsStopped)
                _lastTimeouts[timerIndex] = _timers[timerIndex].GetTime();

            return _lastTimeouts[timerIndex];
        }
        internal static double GetElapsedTime(int timerIndex)
        {
            if (timerIndex >= _nextIndex)
                throw new ArgumentOutOfRangeException("timerIndex", timerIndex, "El valor del parametro timerIndex excede el numero de temporizadores existentes");
            if (_timers[timerIndex] == null) 
                throw new InvalidOperationException();
            if (!_timers[timerIndex].IsStopped)
                _lastElapsed[timerIndex] = _timers[timerIndex].GetElapsedTime();

            return _lastElapsed[timerIndex];
        }
    }
}
